﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.DirectoryServices;
using ActiveDs;

namespace Library
{
  #region LocalUserクラス
  /// <summary>
  /// ローカルのユーザーを表すクラスです。
  /// </summary>
  public sealed class LocalUser : DirectoryObject, IUser
  {
    #region インターナルコンストラクター
    /// <summary>
    /// <see cref="DirectoryEntry"/> を指定して <see cref="LocalUser"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="entry"><see cref="DirectoryEntry"/>。</param>
    internal LocalUser(DirectoryEntry entry)
      : base(entry)
    {
    }
    #endregion

    #region パブリックプロパティ
    /// <summary>
    /// アカウントが無効かどうかを取得します。
    /// </summary>
    public bool Disabled
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return ((IADsUser)base.Entry.NativeObject).AccountDisabled;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        ((IADsUser)base.Entry.NativeObject).AccountDisabled = value;
      }
    }

    /// <summary>
    /// フルネームを取得または設定します。
    /// </summary>
    public string FullName
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["FullName"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["FullName"].Value = value;
      }
    }

    /// <summary>
    /// <see cref="Entry"/> の ADSI User オブジェクトを取得します。
    /// </summary>
    public IADsUser Native
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (IADsUser)base.Entry.NativeObject;
      }
    }
    #endregion
  }
  #endregion

  #region DomainUserクラス
  /// <summary>
  /// ドメインのユーザーを表すクラスです。
  /// </summary>
  [DataObject()]
  public sealed class DomainUser : DomainObject, IUser
  {
    #region プライベートフィールド
    private readonly string _name;
    #endregion

    #region インターナルコンストラクター
    /// <summary>
    /// <see cref="DirectoryEntry"/> を指定して <see cref="DomainUser"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="entry"><see cref="DirectoryEntry"/>。</param>
    internal DomainUser(DirectoryEntry entry)
      : base(entry)
    {
      _name = entry.Properties["sAMAccountName"].Value.ToString();
    }
    #endregion

    #region パブリックプロパティ
    /// <summary>
    /// 電子メールを取得または設定します。
    /// </summary>
    public string EmailAddress
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["mail"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["mail"].Value = value;
      }
    }

    /// <summary>
    /// アカウントが無効かどうかを取得または設定します。
    /// </summary>
    public bool Disabled
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return ((IADsUser)base.Entry.NativeObject).AccountDisabled;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        ((IADsUser)base.Entry.NativeObject).AccountDisabled = value;
      }
    }

    /// <summary>
    /// 表示用の名前を取得します。
    /// </summary>
    public string DisplayName
    {
      get
      {
        return base.Name;
      }
    }

    /// <summary>
    /// 名を取得または設定します。
    /// </summary>
    public string FirstName
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["givenName"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["givenName"].Value = value;
      }
    }

    /// <summary>
    /// 表示名を取得または設定します。
    /// </summary>
    public string FullName
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["displayName"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["displayName"].Value = value;
      }
    }

    /// <summary>
    /// 姓を取得または設定します。
    /// </summary>
    public string LastName
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["sn"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["sn"].Value = value;
      }
    }

    /// <summary>
    /// アカウント名を取得します。
    /// </summary>
    public override string Name
    {
      get
      {
        return _name;
      }
    }

    /// <summary>
    /// <see cref="Entry"/> の ADSI User オブジェクトを取得します。
    /// </summary>
    public IADsUser Native
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (IADsUser)base.Entry.NativeObject;
      }
    }

    /// <summary>
    /// 事業所を取得または設定します。
    /// </summary>
    public string OfficeName
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["physicalDeliveryOfficeName"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["physicalDeliveryOfficeName"].Value = value;
      }
    }

    /// <summary>
    /// プライマリ グループ ID を取得します。
    /// </summary>
    public int PrimaryGroupId
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return Convert.ToInt32(base.Entry.Properties["primaryGroupID"].Value);
      }
    }

    /// <summary>
    /// 電話番号を取得または設定します。
    /// </summary>
    public string TelephoneNumber
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (string)base.Entry.Properties["telephoneNumber"].Value;
      }
      set
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        base.Entry.Properties["telephoneNumber"].Value = value;
      }
    }
    #endregion

    #region パブリックメソッド
    /// <summary>
    /// 指定したアカウント名のユーザーを検索します。このメソッドはデータバインド用です。
    /// </summary>
    /// <param name="name">アカウント名。</param>
    /// <returns>ユーザー。</returns>
    [DataObjectMethod(DataObjectMethodType.Select)]
    public static DomainUser FindByName(string name)
    {
      return (DomainUser)DirectoryAccess.FindDirectoryObject(name, CategoryType.User);
    }

    /// <summary>
    /// 指定したユーザーの所属するグループを取得します。このメソッドはデータバインド用です。
    /// </summary>
    /// <param name="userName">ユーザーのアカウント名。</param>
    /// <returns>ユーザーの所属するグループ。</returns>
    [DataObjectMethod(DataObjectMethodType.Select)]
    public static ReadOnlyCollection<string> GetBelongGroups(string userName)
    {
      var user = FindByName(userName);  //ユーザーを検索
      return DirectoryAccess.GetBelongGroups(user);   //ユーザーの所属するグループを取得
    }

    /// <summary>
    /// ユーザーの一覧を取得します。このメソッドはデータバインド用です。
    /// </summary>
    /// <returns>ユーザーの一覧。</returns>
    [DataObjectMethod(DataObjectMethodType.Select)]
    public static IList<DomainUser> GetUsers()
    {
      return DirectoryAccess.GetUsers<DomainUser>();  //ユーザーを取得
    }

    /// <summary>
    /// 表示用の名前を返します。
    /// </summary>
    /// <returns>表示用の名前。</returns>
    public override string ToString()
    {
      return this.DisplayName;
    }
    #endregion
  }
  #endregion
}
